#!/usr/bin/python
#
# bootstrap
#
# Copyright (C) 2010 Antoine Mercadal <antoine.mercadal@inframonde.eu>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import os, sys, getopt
import threading, time
import ConfigParser
import uuid

REDIRECT = ""#" > /dev/null 2>&1 "


MSG_ARCHIPEL_CLIENT_HEADER = """\
###############################################################################
#                                                                             #
#                            Archipel Client                                  #
#                                                                             #
###############################################################################

Welcome to the installation script of Archipel Client.
Note that you must be root in order to install this software. Please answer the
following questions.

"""

MSG_ARCHIPEL_INIT_SUBMODULES = """\
###############################################################################
#                                                                             #
#                        Archipel Submodules                                  #
#                                                                             #
###############################################################################

It seems that your local copy hasn't its submodules initialized. Bootstrap
will initialize it for you. Please wait.

"""



class Spinner(threading.Thread):

    def __init__(self, delay=0.2):
        threading.Thread.__init__(self);
        self.sequence = ["#   ", "##  ", "### ", "####", " ###", "  ##", "   #", "    " ];
        self.on = True;
        self.delay = delay
        self.start()


    def run(self):
        if REDIRECT == "":
            return
        i = 0
        while self.on:
            sys.stdout.write("\033[33m [%s]\033[0m\r" % self.sequence[i])
            sys.stdout.flush()
            i += 1;
            if i >= len(self.sequence):
                i = 0;
            time.sleep(self.delay)


    def stop(self):
        self.on = False;





### User interaction

def ask(message, answers=None, default=None):
    question = " * " + message
    if answers and default:
        question += " ["
        for a in answers:
            a = a
            if default and a in (default): a = "\033[32m" + a + "\033[0m"
            question += a + "/"
        question = question[:-1]
        question += "]"

    if not answers and default:
        question += " [\033[32m" + default + "\033[0m]"

    question += " : "

    resp = raw_input(question)

    if default:
        if resp == "": resp = default;

    if answers and default:
        if not resp in answers and len(answers) > 0:
            resp = ask("\033[33mYou must select of the following answer\033[0m", answers, default);

    return resp


def ask_bool(message, default="y"):
    if ask(message, ["y", "n"], default) == "y":
        return True
    return False


def test_user_root():
    import getpass
    if not getpass.getuser() == "root":
        print "\033[31m\n * ERROR: You need to be root\033[0m\n"
        sys.exit(1)


def git_init_submodules():
    if not os.path.exists(".submodules_initialized"):
        clear()
        print MSG_ARCHIPEL_INIT_SUBMODULES
        print "\033[35m"
        ret = os.system("cd ../ && git submodule update --init --recursive")
        if ret != 0:
            print "\033[31mUnable to initialize submodules\033[0m"
            sys.exit(1)
        print "\033[32mSubmodule are initialized.\033[0m\n"
        os.system("touch .submodules_initialized")
        confirm = ask("Continue ?", ["y", "n"], "y")
        clear()



### tests / init / Utils

def test_cmd(cmd):
    if os.system("which %s > /dev/null 2>&1" % cmd) != 0:
        return False
    return True


def test_cmd_or_die(cmd, warn=False):
    if not test_cmd(cmd):
        if not warn:
            print "\033[31m\n * ERROR: You need %s\033[0m\n" % cmd
            sys.exit(1)
        else:
            print "\033[33m   - WARNING: You'll need %s to use certains features.\033[0m" % cmd


def test_basic_cmds():
    test_cmd_or_die("git")
    test_cmd_or_die("cp")
    test_cmd_or_die("mkdir")
    test_cmd_or_die("mv")
    test_cmd_or_die("echo")
    test_cmd_or_die("chmod")
    test_cmd_or_die("chown")


def test_install_archipelclient():
    test_basic_cmds()


def clear():
    os.system("clear")




### install client

def install_archipelclient(interactive=True, properties=None):
    clear()
    print MSG_ARCHIPEL_CLIENT_HEADER

    print " Testing environment"
    test_install_archipelclient()
    print ""


    inst_export = None

    if interactive:
        inst_capp           = ask_bool("Would you like to build Cappuccino ?", default="n")
        inst_growl          = ask_bool("Would you like to build GrowlCappuccino ?")
        inst_vnc            = ask_bool("Would you like to build VNCCappuccino ?")
        inst_strophe        = ask_bool("Would you like to build StropheCappuccino ?")
        inst_tnkit          = ask_bool("Would you like to build TNKit ?")
        inst_lpkit          = ask_bool("Would you like to build LPKit ?")
        inst_archipel       = ask_bool("Would you like to build Archipel Client ?")
        inst_appcapp        = ask_bool("Would you like to apply Cappuccino Framework ?")
        if ask_bool("Would you like to export Archipel ?"):
            inst_export     = ask("Where do you want to export Archipel Client ?", None, "~/")
    else:
        inst_capp           = properties["inst_capp"]
        inst_growl          = properties["inst_growl"]
        inst_vnc            = properties["inst_vnc"]
        inst_strophe        = properties["inst_strophe"]
        inst_tnkit          = properties["inst_tnkit"]
        inst_lpkit          = properties["inst_lpkit"]
        inst_archipel       = properties["inst_archipel"]
        if properties["inst_export"]:
            inst_appcapp    = True
            inst_export     = properties["inst_export"]
        else:
            inst_appcapp    = False

    print ""
    print " Installation information"
    print "   - build Cappuccino            : %s" % str(inst_capp)
    print "   - build GrowlCappuccino       : %s" % str(inst_growl)
    print "   - build VNCCappuccino         : %s" % str(inst_vnc)
    print "   - build StropheCappuccino     : %s" % str(inst_strophe)
    print "   - build TNKit                 : %s" % str(inst_tnkit)
    print "   - build LPKit                 : %s" % str(inst_lpkit)
    print "   - build Archipel Client       : %s" % str(inst_archipel)
    print "   - apply Cappuccino            : %s" % str(inst_appcapp)
    if inst_export: print "   - export to                   : %s" % inst_export
    print ""

    if interactive:
        confirm = ask("Do you confirm ?", ["y", "n"], "y")
        if confirm == "n":
            print " \033[33m* Installation canceled by user\033[0m"
            sys.exit(0)

    if inst_capp:
        client_build_cappuccino()
    elif test_cmd("jake") == False:
        print "\033[31mYou don't want to install Cappuccino but it's also not already installed\033[0m"
        sys.exit(1)

    if inst_growl:          client_build_growlcappuccino()
    if inst_vnc:            client_build_vnccappuccino()
    if inst_strophe:        client_build_strophecappuccino()
    if inst_tnkit:          client_build_tnkit()
    if inst_lpkit:          client_build_lpkit()
    if inst_appcapp:        client_apply_cappuccino_frameworks()
    if inst_archipel:       client_build_archipel()
    if inst_export:         client_export_archipel(inst_export)

    print "\033[32m"
    print " Installation is now complete.\n"
    print "\033[0m"

    if interactive: ask_bool("Continue ?")


def client_build_cappuccino():
    print " * Building Cappuccino";
    print "\n\033[35m*******************************************************************************"
    ret = os.system("cd ./Libraries/Cappuccino && ./bootstrap.sh")
    if ret != 0:
        print "\033[31mUnable to bootstrap Cappuccino\033[0m"
        sys.exit(1)
    ret = os.system("cd ./Libraries/Cappuccino && jake install")
    print "*******************************************************************************\033[0m"
    if ret != 0:
        print "\033[31mUnable to build Cappuccino\033[0m"
        sys.exit(1)
    print "\033[32m * Cappuccinno build\033[0m"


def client_build_strophecappuccino():
    print " * Building StropheCappuccino";
    s = Spinner();
    ret = os.system("cd ./Libraries/StropheCappuccino && jake debug  %s && jake release %s" % (REDIRECT, REDIRECT))
    s.stop()
    if ret != 0:
        print "\033[31mUnable to build StropheCappuccino\033[0m"
        sys.exit(1)
    print "\033[32m * StropheCappuccino build\033[0m"


def client_build_growlcappuccino():
    print " * Building GrowlCappuccino";
    s = Spinner();
    ret = os.system("cd ./Libraries/GrowlCappuccino && jake debug  %s && jake release %s" % (REDIRECT, REDIRECT))
    s.stop()
    if ret != 0:
        print "\033[31mUnable to build GrowlCappuccino\033[0m"
        sys.exit(1)
    print "\033[32m * GrowlCappuccino build \033[0m"


def client_build_vnccappuccino():
    print " * Building VNCCappuccino";
    s = Spinner();
    ret = os.system("cd ./Libraries/VNCCappuccino && jake debug  %s && jake release %s" % (REDIRECT, REDIRECT))
    s.stop()
    if ret != 0:
        print "\033[31mUnable to build Cappuccino\033[0m"
        sys.exit(1)
    print "\033[32m * VNCCappuccino build\033[0m"


def client_build_lpkit():
    print " * Building LPKit";
    s = Spinner();
    ret = os.system("cd ./Libraries/LPKit && export CAPP_BUILD=./Build && export CONFIGURATION=Release && jake build %s && export CONFIGURATION=Debug && jake build %s" % (REDIRECT, REDIRECT))
    s.stop()
    if ret != 0:
        print "\033[31mUnable to build LPKit\033[0m"
        sys.exit(1)
    print "\033[32m * LPKit build\033[0m"


def client_build_tnkit():
    print " * Building TNKit";
    s = Spinner();
    ret = os.system("cd ./Libraries/TNKit && export CAPP_BUILD=./Build && jake debug  %s && jake release %s"  % (REDIRECT, REDIRECT))
    s.stop()
    if ret != 0:
        print "\033[31mUnable to build TNKit\033[0m"
        sys.exit(1)
    print "\033[32m * TNKit build\033[0m"


def client_build_archipel(exportpath=None):
    if exportpath:
        export = " --export=%s" % exportpath
    else:
        export = ""
    print " * Building ArchipelClient"
    s = Spinner();
    os.system("./buildArchipel -bag --config=release %s %s" % (export, REDIRECT))
    s.stop()
    print "\033[32m * ArchipelClient built\033[0m"


def client_apply_cappuccino_frameworks():
    print " * Adding Cappuccino framework"
    s = Spinner();
    os.system("capp gen -f . %s" % REDIRECT)
    s.stop()
    print "\033[32m * Cappuccino added\033[0m"


def client_export_archipel(path):
    print " * Exporting archipel to %s" % path
    os.system("mkdir -p %s %s" % (path, REDIRECT))
    s = Spinner();
    os.system("cp -a ./Build/Release/Archipel %s %s" % (path, REDIRECT))
    s.stop()
    print "\033[32m * Archipel Client exported\033[0m"






### Main

def main(interactive=True, properties=None):
    try:
        clear()

        print MSG_ARCHIPEL_CLIENT_HEADER

        #test_user_root()
        git_init_submodules()
        print " "

        if interactive:
            confirm = ask("Do want to start installation ?", ["y", "n"], "y")
            if confirm == "n":
                print " \033[33m* Installation canceled by user\033[0m"
                sys.exit(0)

        install_archipelclient(interactive, properties)
        clear()
    except KeyboardInterrupt:
        print "\n\n\033[33m * Installation canceled by user\033[0m\n"



if __name__ == "__main__":
    try:
        opts, args = getopt.getopt(sys.argv[1:], "", [  "notinteractive",
                                                        "cappuccino",
                                                        "growlcappuccino",
                                                        "vnccappuccino",
                                                        "strophecappuccino",
                                                        "lpkit",
                                                        "tnkit",
                                                        "archipel",
                                                        "export="])
    except getopt.GetoptError, err:
        print str(err)
        #usage()
        sys.exit(2);

    interactive = True

    properties = {}
    properties["inst_capp"]             = False
    properties["inst_growl"]            = False
    properties["inst_vnc"]              = False
    properties["inst_strophe"]          = False
    properties["inst_lpkit"]            = False
    properties["inst_tnkit"]            = False
    properties["inst_archipel"]         = False
    properties["inst_export"]           = None


    for o, a in opts:
        if o in ("--notinteractive"):
            interactive = False

        if not interactive and o in ("--cappuccino"):           properties["inst_capp"]             = True
        if not interactive and o in ("--growlcappuccino"):      properties["inst_growl"]            = True
        if not interactive and o in ("--vnccappuccino"):        properties["inst_vnc"]              = True
        if not interactive and o in ("--strophecappuccino"):    properties["inst_strophe"]          = True
        if not interactive and o in ("--lpkit"):                properties["inst_lpkit"]            = True
        if not interactive and o in ("--tnkit"):                properties["inst_tnkit"]            = True
        if not interactive and o in ("--archipel"):             properties["inst_archipel"]         = True
        if not interactive and o in ("--export"):               properties["inst_export"]           = a


    main(interactive, properties)





